#include <ctime>
#include <iostream>
#include "igslib_iutil.h"
#include "igslib_iexternal_board.h"
#include "igslib_iserial_manager.h"


#include<fstream>
#include<cstring>

namespace igslib
{
    namespace external_board_sample
    {

        static void MCU_FW_Upgrade()
        {
            ISerialManager* srm = GetSerialManagerInstance();
            IUart* uart = srm->NewM01Uart();
            IUart::DeviceNumber dn = IUart::ttyS3;
            uart->SetBaudRate(115200);
            bool odr = uart->Open(dn); // open device result
            std::cout << "Open device[" << dn << "]: " << odr << std::endl;	
			
            IExternalBoardManager* ebm = GetExternalBoardManagerInstance();
            IExternalBoard* exb = ebm->New_MH_MCU();
            exb->SetUART(uart);
							
			std::string MCUImagBurn="MCU_Test_V100.bin";
			
			if(true)
			{
				std::ifstream fp;
				fp.open(MCUImagBurn, std::ios::in | std::ios::binary | std::ios::ate );		
				if(!fp)		
				throw_igslib_exception("MCU_FW_Upgrade, open ImgBurn fail");			
				
				// get length of file & valid data length:
				fp.seekg (0, fp.end);  //offset:0  start pos: file end
				int flen = fp.tellg(); //locate pos
				fp.seekg (0);
				char* buffer= (char*)malloc(flen); 	
				fp.read(buffer,flen);
				
				exb->ImportRawData(buffer,flen);
				
				delete(buffer);			
				fp.close();
			}
			else
				exb->SetSourceDst(MCUImagBurn);
			
		 
			
            std::string source_str=exb->GetSourceVersion();
            std::string mcu_str=exb->GetVersion();

            std::cout << "Source Revision: "<< source_str << std::endl;
            std::cout << "MCU Revision: "<< mcu_str << std::endl;

            if ( mcu_str == source_str)
            {
                std::cout << "the same"<<  std::endl;
            }
            else
            {
                std::cout << "different"<<  std::endl;
            }
            exb->Upgrade();
            uart->Close();
            exit(EXIT_SUCCESS);
        }


        static void IKV_test()
        {
            ISerialManager* srm = GetSerialManagerInstance();
            //ISpi* spi = srm->NewM01Spi();
            ISpi* spi = srm->New_ProjMCU_spi("DragonBallRace");
            spi->SetWorkingFrequency(10000000);
            bool open_result = spi->Open(ISpi::cs0);

            char txbuf[256]={11};
            char rxbuf[256];


            IExternalBoardManager* ebm = GetExternalBoardManagerInstance();
            IExternalBoard* exb = ebm->New_ProjMCU("DragonBallRace");
            exb->SetSPI(spi);

            char chipid[92];
            static float rtn = 0;
            unsigned long long delta;
            static unsigned long long d0 = util::GetTicks();
            static unsigned long long d1 = util::GetTicks();
            static unsigned long long d2 = util::GetTicks();
            static unsigned long long d3 = util::GetTicks();

            int time_idx=0;           
            int init_flg=0;
            unsigned char memory=0;

            int ikv_Request_Action=0;		
            IProtectUnit* ikv=exb->GetProtectUnit();

            while(1)
            {
                d1 = util::GetTicks();
                delta= d1-d0;
                if (delta >= 16)
                {
                    d0 = util::GetTicks();
                    spi->Update();
                }

                d3 = util::GetTicks();
                delta= d3-d2;
                if (delta >= 1000)
                {
                    d2=util::GetTicks();
                    time_idx++;

                    //初始化 IKV 已取得ikv information
                    if(init_flg==0)
                    {
                        ikv->ProtectEnable();   
                        init_flg=1;
                    }						  
                    if(time_idx == 2) //2s
                    {
                        if(ikv_Request_Action==0)
                        {
                            std::vector<char> addresses;
                            addresses.push_back(0);											
                            bool request=ikv->SendRequest("authenticate",addresses);
                            if (request==true)
                            {							  
                                ikv_Request_Action=1;
                                std::cout<<"authenticate request start "<<std::endl;
                            }
                            else  
                                std::cout<<"authenticate request Fail "<<std::endl;
                        }
                    }
                    else if(time_idx == 7) //存款
                    {
                        if(ikv_Request_Action==0)
                        {
                            std::vector<char> addresses;
                            addresses.push_back(0);											
                            bool request=ikv->SendRequest("deposit",addresses);
                            if (request==true)
                            {							  
                                ikv_Request_Action=2;
                                std::cout<<"deposit request start "<<std::endl;
                            }
                            else			  
                                std::cout<<"deposit request Fail "<<std::endl;
                        }
                    }
                    else if(time_idx==13) //提款
                    {
                        if(ikv_Request_Action==0)
                        {
                            std::vector<char> addresses;
                            addresses.push_back(0);											
                            bool request=ikv->SendRequest("withdraw",addresses);
                            if (request==true)
                            {							  
                                ikv_Request_Action=3;
                                std::cout<<"withdraw request start "<<std::endl;
                            }
                            else		  
                                std::cout<<"withdraw request Fail "<<std::endl;
                        }
                        time_idx=0;
                    }



                    if(ikv_Request_Action==1)
                    {
                        if (ikv->GetState() == IProtectUnit::State::Idle  )
                        {
                            bool AUTH = ikv->Authenticate();
                            if(AUTH == true)
                                std::cout<<"IKV_Authenticate: TRUE "<<std::endl<<std::endl; 
                            else
                                std::cout<<"IKV_Authenticate: FALSE "<<std::endl<<std::endl;  
                            ikv_Request_Action=0;		
                        }
                        else
                            std::cout<<"IKV IS BUSY"<<std::endl; 	


                    }
                    else if(ikv_Request_Action==2)
                    {
                        if (ikv->GetState() == IProtectUnit::State::Idle  )
                        {

                            std::vector<char> accout;
                            for(int i=0;i<16;i++)
                                accout.push_back(memory);
                            memory++;
                            ikv->Deposit(accout);

                            std::cout<<"IKV Writing ROM: ";
                            for(int i=0;i<16;i++)
                                printf("0x%02x,",accout[i]);
                            std::cout<<std::endl<<std::endl; 


                            ikv_Request_Action=0;		
                        }
                        else
                            std::cout<<"IKV IS BUSY"<<std::endl; 			  
                    }
                    else if(ikv_Request_Action==3)
                    {
                        if (ikv->GetState() == IProtectUnit::State::Idle  )
                        {

                            auto result = ikv->Withdraw();
                            std::cout<<"IKV Read ROM: ";
                            for(int i=0;i<16;i++)
                                printf("0x%02x,",result[i]);
                            std::cout<<std::endl<<std::endl<<std::endl<<std::endl;						
                            ikv_Request_Action=0;		
                        }
                        else
                            std::cout<<"IKV IS BUSY"<<std::endl; 			  
                    }

                }

            }

            exit(EXIT_SUCCESS);
        }	

        static void protect_unit_authenticate_only()
        {
            ISerialManager* srm = GetSerialManagerInstance();
            //ISpi* spi = srm->NewM01Spi();	
            ISpi* spi = srm->New_ProjMCU_spi("DragonBallRace");
            spi->SetWorkingFrequency(10000000);
            bool open_result = spi->Open(ISpi::cs0);
            if (open_result == false)
            {
                throw_igslib_exception("open spi fail.");
            }

            IExternalBoardManager* ebm = GetExternalBoardManagerInstance();
            IExternalBoard* exb = ebm->New_ProjMCU("DragonBallRace");
            exb->SetSPI(spi);
            IProtectUnit* ikv=exb->GetProtectUnit();

            enum phase
            {
                wait_wakeup,
                send_request,
                wait_request,
                authenticate,
                wait_authenticate,
                finish,
            } now_phase;

            now_phase = (phase)0;
            util::Log("%s>\n",__func__);

            util::Log("wait wakeup ...");
            while(util::KbHit() != 27)
            {
                if (now_phase == wait_wakeup)
                {
                    if (ikv->GetState() == IProtectUnit::State::Idle)
                    {
                        util::Log("ok\n");
                        now_phase = send_request;
                    }
                }
                else if (now_phase == send_request)
                {
                    std::vector<char> tmp;
                    util::Log("send request ...");
                    bool result = ikv->SendRequest("authenticate",tmp);
                    if (result)
                    {
                        now_phase = wait_request;
                        util::Log("ok\n");
                        util::Log("wait request ...");
                    }
                    else
                    {
                        now_phase = finish;
                        util::Log("fail.\n");
                    }
                }
                else if (now_phase == wait_request)
                {
                    if (ikv->GetState() == IProtectUnit::State::Idle)
                    {
                        now_phase = authenticate;
                        util::Log("ok\n");
                    }
                    else
                    {
                        util::Log(".");
                    }
                }
                else if (now_phase == authenticate)
                {
                    util::Log("authenticate...");
                    bool result = ikv->Authenticate();
                    if (result)
                    {
                        util::Log("ok\n");
                        now_phase = wait_authenticate;
                        util::Log("wait authenticate ...");
                    }
                    else
                    {
                        util::Log("fail\n");
                        now_phase = finish;
                    }
                }
                else if (now_phase == wait_authenticate)
                {
                    if (ikv->GetState() == IProtectUnit::State::Idle)
                    {
                        now_phase = finish;
                        util::Log("ok\n");
                    }
                    else
                    {
                        util::Log(".");
                    }
                }
                else if (now_phase == finish)
                {
                    util::Log("\n=== session over ===\n");
                    break;
                }
                spi->Update();
                util::SleepMSTime(16);
            }

            spi->Close();
            delete srm;
            delete ebm;
        }
    };
};
